package jp.sourceforge.talisman.csvio.builder;

/*
 * $Id: QuoteAsNeededCsvLineBuilder.java,v 1.1 2009/09/12 05:06:11 weiwei Exp $
 */

import java.util.ArrayList;
import java.util.List;

import jp.sourceforge.talisman.csvio.CsvIOSetting;
import jp.sourceforge.talisman.csvio.EscapeMode;

/**
 * 
 * @author Haruaki Tamada
 * @version $Revision: 1.1 $ $Date: 2009/09/12 05:06:11 $
 */
class QuoteAsNeededCsvLineBuilder extends AbstractCsvLineBuilder{
    public QuoteAsNeededCsvLineBuilder(){
    }

    public QuoteAsNeededCsvLineBuilder(CsvIOSetting setting){
        super(setting);
    }

    @Override
    protected List<String> splitToTokens(String line){
        List<String> strings;
        CsvIOSetting setting = getSetting();

        if(setting.getEscapeMode() == EscapeMode.ESCAPE_CHARACTER){
            strings = splitToTokensEscapeChar(line, setting);
        }
        else{
            strings = splitToTokensDoubleEscapeChar(line, setting);
        }
        return strings;
    }

    private List<String> splitToTokensDoubleEscapeChar(String line, CsvIOSetting setting){
        List<String> strings = new ArrayList<String>();
        StringBuilder sb = new StringBuilder();
        int length = line.length();
        int current = 0;
        boolean quote = false;
        char QB = setting.getQuoteBegin();
        char QE = setting.getQuoteEnd();

        while(current < length){
            char c = line.charAt(current);
            current++;
            if(c == QB){
                if(current < length && line.charAt(current) == QB){
                    sb.append(c);
                    current++;
                }
                else if(quote && c == QE){
                    quote = false;
                }
                else{
                    quote = true;
                }
            }
            else if(c == QE){
                if(current < length && line.charAt(current) == QE){
                    sb.append(c);
                    current++;
                }
                else{
                    quote = false;
                }
            }
            else if(c == setting.getSeparator()){
                if(quote){
                    sb.append(c);
                }
                else{
                    strings.add(new String(sb));
                    sb.delete(0, sb.length());
                    quote = false;
                }
            }
            else{
                sb.append(c);
            }
        }
        strings.add(new String(sb));
        sb.delete(0, sb.length());

        return strings;
    }

    private List<String> splitToTokensEscapeChar(String line, CsvIOSetting setting){
        List<String> strings = new ArrayList<String>();
        StringBuilder sb = new StringBuilder();
        int length = line.length();
        boolean quotation = false;
        boolean escape = false;

        for(int i = 0; i < length; i++){
            char c = line.charAt(i);
            if(escape){
                sb.append(c);
                escape = false;
            }
            else if(quotation){
                if(c == setting.getEscapeCharacter()){
                    escape = true;
                }
                else if(c == setting.getQuoteEnd()){
                    quotation = false;
                }
                else{
                    sb.append(c);
                }
            }
            else{
                if(c == setting.getQuoteBegin()){
                    quotation = true;
                }
                else if(c == setting.getEscapeCharacter()){
                    escape = true;
                }
                else if(c == setting.getSeparator()){
                    strings.add(new String(sb));
                    sb.delete(0, sb.length());
                }
                else{
                    sb.append(c);
                }
            }
        }
        strings.add(new String(sb));
        sb.delete(0, sb.length());

        return strings;
    }
}
